package rtda

import (
	"hi-jvm/rtda/heap"
	"math"
)

// 操作数栈
// 操作数栈的大小是编译器已经确定的
type OperandStack struct {
	size uint	// 记录栈顶位置
	slots []Slot
}

func newOperandStack(maxStack uint) *OperandStack {
	if 0 == maxStack {
		return nil
	}
	return &OperandStack{
		slots: make([]Slot, maxStack),
	}
}

func (self *OperandStack)PushInt(val int32) {
	self.slots[self.size].Num = val
	self.size++
}

func (self *OperandStack)PopInt() int32 {
	self.size--
	return self.slots[self.size].Num
}

func (self *OperandStack)PushFloat(val float32) {
	bits := math.Float32bits(val)
	self.slots[self.size].Num = int32(bits)
	self.size++
}

func (self *OperandStack)PopFloat() float32 {
	self.size--
	bits := uint32(self.slots[self.size].Num)
	return math.Float32frombits(bits)
}

func (self *OperandStack)PushLong(val int64) {
	self.slots[self.size].Num = int32(val)
	self.slots[self.size + 1].Num = int32(val) >> 32;
	self.size += 2
}

func (self *OperandStack)PopLong() int64 {
	self.size -= 2
	low := uint32(self.slots[self.size].Num)
	high := uint32(self.slots[self.size  + 1].Num)
	return int64(high) << 32 | int64(low)
}


func (self *OperandStack)PushDouble(val float64) {
	bits := math.Float64bits(val)
	self.PushLong(int64(bits))
}

func (self *OperandStack)PopDouble() float64 {
	bits := uint64(self.PopLong())
	return math.Float64frombits(bits)
}


func (self *OperandStack)PushRef(val *heap.Object) {
	self.slots[self.size].Ref = val
	self.size++
}

func (self *OperandStack)PopRef() *heap.Object {
	self.size--
	ref := self.slots[self.size].Ref
	self.slots[self.size].Ref = nil
	if ref == nil {
		panic("java.lang.NullPointerException")
	}
	return ref
}

// 入栈
func (self *OperandStack)PushSlot(slot Slot) {
	self.slots[self.size] = slot
	self.size++
}

// 出栈
func (self *OperandStack)PopSlot() Slot {
	self.size--
	return self.slots[self.size]
}

// 返回距离操作栈顶n个单元格的引用变量
// GetRefFromTop(0)返回操作数栈顶引用
// GetRefFromTop(4)返回距离操作数栈顶4个单元的引用
func (self *OperandStack) GetRefFromTop(n uint) *heap.Object {
	return self.slots[self.size-1-n].Ref
}
